package com.yueyang.sojourn.server.service.sojourn.pay;

import com.github.binarywang.wxpay.bean.profitsharing.ProfitSharingReceiverResult;
import com.github.binarywang.wxpay.bean.result.WxPayOrderCloseResult;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult;
import com.github.binarywang.wxpay.bean.result.WxPayRefundQueryResult;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.pagehelper.PageInfo;
import com.yueyang.sojourn.server.model.enums.*;
import com.yueyang.sojourn.server.model.po.*;
import com.yueyang.sojourn.server.service.sojourn.merchant.SojournMerchantService;
import com.yueyang.sojourn.server.service.sojourn.order.SojournOrderService;
import com.yueyang.sojourn.server.service.sojourn.projectshare.SojournProjectShareService;
import com.yueyang.sojourn.server.service.sojourn.share.SojournShareService;
import com.yueyang.sojourn.server.service.sojourn.transaction.SojournTransactionService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
@Slf4j
public class PayJob {
    @Autowired
    private SojournTransactionService transactionService;
    @Autowired
    private PayServiceWill payService;
    @Autowired
    private SojournProjectShareService projectShareService;
    @Autowired
    private SojournShareService shareService;
    @Autowired
    private SojournOrderService orderService;
    @Autowired
    private SojournMerchantService merchantService;
    @Autowired
    private ApplicationContext context;

    /**
     * 定时同步支付订单结果
     */
    @Scheduled(cron = "0 0/2 * * * ?")
    public void syncPaidResultJob() {
        log.info("定时任务 同步支付结果 开始");
        this.syncPaidResultFromWX();
        log.info("定时任务 同步支付结果 结束");
    }

    /**
     * 定时同步订单退款结果
     */
//    @Scheduled(cron = "0 0/2 * * * ?")
    public void syncRefundResultJob() {
        log.info("定时任务 同步退款结果 开始");
        this.syncRefundResultFromWX();
        log.info("定时任务 同步退款结果 结束");
    }

    /**
     * 定时同步分账方
     */
    @Scheduled(cron = "0 0/2 * * * ?")
    public void syncShareMerchantResultJob() {
        log.info("定时任务 同步分账 开始");
        this.syncShareMerchantToWx();
        log.info("定时任务 同步分账 结束");
    }

    /**
     * 订单过期:从下单到支付1个小时，1小时内不支付，则过期
     */
    @Scheduled(cron = "0 0/1 * * * ?")
    public void orderStatusJob() {
        log.info("定时任务 订单过期 开始");
        this.orderStatusExpire();
        log.info("定时任务 订单过期 结束");
    }

    /**
     * 订单：订单分账
     */
    @Scheduled(cron = "0 0/2 * * * ?")
    public void toShareJob() {
        log.info("定时任务 订单分账 开始");
        this.toShare();
        log.info("定时任务 订单分账 结束");
    }

    /**
     * 订单即将过期提醒用户
     */
    @Scheduled(cron = "0 0/1 * * * ?")
    public void orderWillExprieInTimeJob() {
        log.info("定时任务 订单即将过期提醒 开始");
        this.orderWillExprieInTime();
        log.info("定时任务 订单即将过期提醒 结束");
    }


    /**
     * 从微信同步支付结果
     */
    public void syncPaidResultFromWX() {
        // 一次获取50个
        int pageSize = 50;
        //查询状态为待支付的交易
        PageInfo<SojournTransaction> prepayTransPage = this.transactionService.findPage(null, PayConstants.TransactionStatusEnum.PAYING.getCode(),1,pageSize);

        for(SojournTransaction transaction : prepayTransPage.getList()) {
            if(transaction.getStatus() == null ||
                    PayConstants.TransactionStatusEnum.PAYING.getCode() != transaction.getStatus()){
                continue;
            }

            //查询微信支付结果
            WxPayOrderQueryResult orderPayRs = null;
            try {
                orderPayRs = payService.queryOrder(transaction);

                //更新本地交易状态 -
                payService.paid(orderPayRs);
            }catch (Exception e){
                log.error(e.getMessage(),e);
                continue;
            }
        }
    }

    /**
     * 从微信同步退款结果
     */
    public void syncRefundResultFromWX() {
        // 一次获取50个
        int pageSize = 50;
        //查询状态为待支付的交易
        PageInfo<SojournTransaction> prepayTransPage = this.transactionService.findPage(null, PayConstants.TransactionStatusEnum.REFUNDING.getCode(),1,pageSize);

        for(SojournTransaction transaction : prepayTransPage.getList()) {
            if(transaction.getStatus() == null ||
                    PayConstants.TransactionStatusEnum.REFUNDING.getCode() != transaction.getStatus()){
                continue;
            }

            //查询微信支付结果
            WxPayRefundQueryResult orderRefundRs = null;
            try {
                orderRefundRs = payService.refundQuery(transaction.getRefundSn());
                payService.refundResultOperate(transaction.getOrderSn(),orderRefundRs.getRefundRecords().get(0).getRefundId());
            }catch (Exception e){
                log.error(e.getMessage(),e);
                continue;
            }
        }
    }

    /**
     * 项目分账方：同步到微信
     */
    public void syncShareMerchantToWx() {
        // 一次获取50个
        int pageSize = 50;
        //查询状态为待同步的分账单
        PageInfo<SojournProjectShare> sharePageInfo = this.projectShareService.findPage(null, null,ProjectShareThirdSynStatusEnum.TO_SYN.getCode(),1,pageSize);

        for(SojournProjectShare share : sharePageInfo.getList()) {
            //如果状态不正确，则不处理
            if(share.getThirdSynStatus() == null ||
                    ProjectShareThirdSynStatusEnum.TO_SYN.getCode() != share.getThirdSynStatus()){
                continue;
            }
            //如果分账方为自己，则不处理
            SojournMerchant merchantOwner = merchantService.findByProjectId(share.getProjectId());
            if(share.getReceiverId().equals(merchantOwner.getId())){
                //如果是自己，直接更新为已同步（因为自己不需要同步）
                projectShareService.updateThirdSynStatus(share.getId(),ProjectShareThirdSynStatusEnum.SYNED);
                continue;
            }

            //查询微信支付结果
            ProfitSharingReceiverResult receiverResult = null;
            try {
                if(StatusEnum.INVALID.getCode() == share.getStatus()){
                    receiverResult = payService.removeWxShareReceiver(share);
                }else {
                    receiverResult = payService.addWxShareReceiver(share);
                }


                if(!WxPayConstants.ResultCode.SUCCESS.equals(receiverResult.getResultCode())){
//                logger.error(xmlResult);
                    throw new WxPayException("微信删除分账账户失败！");
                }
                if(!WxPayConstants.ResultCode.SUCCESS.equals(receiverResult.getReturnCode())){
//                logger.error(xmlResult);
                    if((!receiverResult.getErrCode().equals("INVALID_REQUEST") || !receiverResult.getErrCodeDes().contains("分账接收商户不存在"))
                       && !receiverResult.getErrCode().equals("USER_NOT_EXIST")){
                        throw new WxPayException("微信删除分账账户失败！");
                    }
                }
                //同步设置本协同步状态(上面不成功会报错)
                projectShareService.updateThirdSynStatus(share.getId(),ProjectShareThirdSynStatusEnum.SYNED);
            }catch (Exception e){
                if(e instanceof WxPayException){
                    WxPayException wxPayException = (WxPayException) e;
                    if(("INVALID_REQUEST".equals(wxPayException.getErrCode()) && "分账接收商户不存在".equals(wxPayException.getErrCodeDes()))
                            || wxPayException.getErrCode().equals("USER_NOT_EXIST")){
                        projectShareService.updateThirdSynStatus(share.getId(),ProjectShareThirdSynStatusEnum.SYNED);
                    }else if("MCH_NOT_EXISTS".equals(wxPayException.getErrCode())){//todo 商户不存在特殊处理
                        projectShareService.updateThirdSynStatus(share.getId(),ProjectShareThirdSynStatusEnum.SYNED);
                    }
                }
                log.error(e.getMessage(),e);
                continue;
            }
        }
    }

    /**
     * 根据分账单：开始分账
     */
    public void toShare() {
        // 一次获取50个
        int pageSize = 50;
        //查询状态为待同步的分账单
        PageInfo<SojournShare> sharePageInfo = this.shareService.findPage(null, ShareConstans.ShareStatusEnum.TO_SHARE.getCode(),1,pageSize);

        for(SojournShare share : sharePageInfo.getList()) {
            if(share.getStatus() == null ||
                    ShareConstans.ShareStatusEnum.TO_SHARE.getCode() != share.getStatus()){
                continue;
            }

            //分账
            ProfitSharingReceiverResult receiverResult = null;
            try {
                //同步设置本协同步状态(上面不成功会报错)
                payService.shareOne(share);
            }catch (Exception e){
                log.error(e.getMessage(),e);
                continue;
            }
        }
    }

    /**
     * 订单过期：如果订单为待支付，但是因为已经支付，支付结果还没出来呢？todo --
     * 同时调一个交易付款交易是否存在，如果交易不存在，直接过期；
     * 如果交易存在，再调一下微信接口查看交易结果；如果也没有结果，直接过期；否则更新已支付；
     */
    public void orderStatusExpire() {
        // 一次获取50个
        int pageSize = 50;
        //查询状态为待支付的订单：
        PageInfo<SojournOrder> orderPageInfo = this.orderService.findWillExpireToPayPage(1,pageSize);

        for(SojournOrder order : orderPageInfo.getList()) {
            if(order.getStatus() == null ||
                    OrderStatusEnum.TO_BE_PAY.getCode() != order.getStatus()){
                continue;
            }

            //更新订单过期状态：如果没有交易记录，说明没有预支付，即不是正在支付中，即不是在等待支付结果，则直接过期
            SojournTransaction transaction = transactionService.findPayByOrderSn(order.getSn());
            if(transaction == null){
                orderService.updateClosedAndTransClosed(order.getId(), null,-1L);
            }else{
                try {
                    WxPayOrderQueryResult orderPayResult = payService.queryOrder(transaction);
                    if(!PayConstants.TradeStateEnum.SUCCESS.getCode().equals(orderPayResult.getTradeState())){
                        if(PayConstants.TradeStateEnum.CLOSED.getCode().equals(orderPayResult.getTradeState())){
                            //关闭订单
                            orderService.updateClosedAndTransClosed(order.getId(), transaction.getId(), -1L);
                        }else {
                            WxPayOrderCloseResult closeResult = payService.closeOrder(transaction);
                            if (
                                    (WxPayConstants.ResultCode.SUCCESS.equals(closeResult.getResultCode())
                                            && WxPayConstants.ResultCode.SUCCESS.equals(closeResult.getReturnCode()))
                                            || ("ORDERCLOSED".equals(closeResult.getErrCode())
                                                || "CLOSED".equals(closeResult.getErrCode()))
                            ) {
                                //关闭订单
                                orderService.updateClosedAndTransClosed(order.getId(), transaction.getId(), -1L);

                            }
                        }
                    }
                }catch (Exception e){
                    log.error(e.getMessage(),e);
                }
            }

        }
    }

    /**
     * 订单15分钟即将过期，发短信提醒
     * 提前一分钟执行
     */
    public void orderWillExprieInTime() {
        // 一次获取50个
        int pageSize = 50;
        //查询状态为待支付的订单：
        PageInfo<SojournOrder> orderPageInfo = this.orderService.findWillExpireToPayInTimePage(16,1,pageSize);

        for(SojournOrder order : orderPageInfo.getList()) {
            if(order.getStatus() == null ||
                    OrderStatusEnum.TO_BE_PAY.getCode() != order.getStatus()){
                continue;
            }

            SojournOrderEvent event = new SojournOrderEvent(this);
            event.setOrderId(order.getId());
            event.setType(OrderEventTypeEnum.TO_BE_PAY_EXPRIE.getCode());
            context.publishEvent(event);
            //发过的不再发送
            orderService.updateMsgStatus(order.getId(),OrderMsgStatusEnum.SENDED.getCode(),-1L);
        }
    }
}
